package de.devisnik.mine.robot;

import java.util.ArrayList;
import java.util.List;

import de.devisnik.mine.IField;
import de.devisnik.mine.IGame;

public class FieldResolver {
	private final IField itsField;
	private final IGame itsGame;
	private List itsPossibleResolutions;
	private IConfiguration itsSaveSolution;

	public FieldResolver(IField field, IGame game) {
		this.itsField = field;
		this.itsGame = game;
	}

	public IField getField() {
		return itsField;
	}
	public List getPossibleResolutions() {
		if (itsPossibleResolutions != null) {
			return itsPossibleResolutions;
		}
		itsPossibleResolutions = new ArrayList();
		final int countClosedUnflaggedNeighbors = countClosedUnflaggedNeighbors();
		final int countNeighborsToFlag = countNeighborsToFlag();
		IConfiguration configuration = ConfigurationFactory.create(
				countClosedUnflaggedNeighbors, countNeighborsToFlag);
		while (configuration != null) {
			if (configuration.test(itsGame, itsField)) {
				itsPossibleResolutions.add(configuration);
			}
			configuration = configuration.next();
		}
		return itsPossibleResolutions;
	}

	public IConfiguration getUniqueResolution() {
		if (itsSaveSolution == null) {
			itsSaveSolution = getIntersection(getPossibleResolutions());
		}
		return itsSaveSolution;
	}

	public IMove[] applyUniqueResolution() {
		if (getUniqueResolution() == null) {
			return new IMove[0];
		}
		return getUniqueResolution().apply(itsGame, itsField);
	}
	
	public IMove[] applyFirstPossibleResolution() {
		if (getPossibleResolutions().isEmpty()) {
			return new IMove[0];
		}
		IConfiguration configuration = (IConfiguration) getPossibleResolutions().get(0);
		return configuration.apply(itsGame, itsField);
	}

	private IConfiguration getIntersection(final List resolvers) {
		if (resolvers.size() == 0) {
			return null;
		}
		IConfiguration intersection = (IConfiguration) resolvers.get(0);
		for (int i = 1; i < resolvers.size(); i++) {
			final IConfiguration configuration = (IConfiguration) resolvers
					.get(i);
			intersection = intersection.getIntersection(configuration);
			if (intersection == null) {
				return null;
			}
		}
		// MineActivator.getDefault().log(
		// "intersection of resolvers: " + resolvers.size());
		return intersection;
	}

	private int countClosedUnflaggedNeighbors() {
		final IField[] neighbors = itsField.getNeighbors();
		int count = 0;
		for (int i = 0; i < neighbors.length; i++) {
			if (!neighbors[i].isOpen() && !neighbors[i].isFlagged()) {
				count++;
			}
		}
		return count;
	}

	private int countNeighborsToFlag() {
		return itsField.getNeighborBombs() - countFlaggedNeighbors();
	}

	private int countFlaggedNeighbors() {
		final IField[] neighbors = itsField.getNeighbors();
		int count = 0;
		for (int i = 0; i < neighbors.length; i++) {
			if (neighbors[i].isFlagged()) {
				count++;
			}
		}
		return count;
	}

}
